package com.YOUtils.File;

import com.YOUtils.Base.Str.YoStringUtils;
import com.YOUtils.YException.YClassException;
import com.YOUtils.YException.YFileNotFound;
import com.YOUtils.YException.YNullPointerException;
import org.w3c.dom.*;
import org.xml.sax.SAXException;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.*;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Objects;

/**
 * Created on 2023/6/16
 *
 * @Time 11:11
 * @Program YOUilt
 * @Author YoHaNe/XiaoShuai
 */
public class YOMLUtils {

    /**
     * 自动生成类xml 将类的属性成员和数值生成xml
     * 如User类中有 name 属性成员 并 name的值为XS
     * 则生成的xml为
     * <User><name>XS<name/><User/>
     * @param o 对象
     * @param path 存放文件路径
     */
    public static void createXMLForBean(Object o,String path){
        if(o == null || YoStringUtils.isEmpty(path))
            throw new YNullPointerException();
        File file = new File(path);
        if(!file.exists())
            throw new YFileNotFound(path);
        try {
            String name = o.getClass().getSimpleName();
            Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
            document.setXmlStandalone(true);
            Element bean = document.createElement(name);
            Class<?> clz = o.getClass();
            Field[] fields = clz.getDeclaredFields();
            for (Field field : fields) {
                field.setAccessible(true);
                Element fileDoc = document.createElement(field.getName());
                fileDoc.setTextContent(String.valueOf(field.get(o)));
                bean.appendChild(fileDoc);
            }
            document.appendChild(bean);
            Transformer tf = TransformerFactory.newInstance().newTransformer();
            tf.setOutputProperty(OutputKeys.INDENT,"yes");
            tf.transform(new DOMSource(document),new StreamResult(new File(path + "\\" + name + ".xml")));
        } catch (ParserConfigurationException | IllegalAccessException | TransformerException e) {
            e.printStackTrace();
        }
    }

    /**
     * 注入bean
     * 现只支持一些基本类型的属性注入
     * @param xml xml路径
     * @return 实体类
     */
    public static Object getBean(String xml){
        if(xml == null || YoStringUtils.isAllChinese(xml))
            throw new YNullPointerException();
        if(!new File(xml).exists())
            throw new YFileNotFound(xml);
        Object o = null;
        try {
            DocumentBuilder db = DocumentBuilderFactory.newInstance().newDocumentBuilder();
            Document dc = db.parse(xml);
            Element cr = dc.getDocumentElement();
            Class<?> clz = Class.forName(cr.getAttribute("path"));
            o = clz.newInstance();
            Field[] fields = clz.getDeclaredFields();
            NodeList fieldList = dc.getElementsByTagName("field");
            for(int i=0;i < fieldList.getLength();i++){
                Node field = fieldList.item(i);
                NamedNodeMap attrs = field.getAttributes();
                for (Field value : fields) {
                    Node attr = attrs.item(0);
                    Field f;
                    if (Objects.equals(attr.getNodeValue(), (f = value).getName())) {
                        Class<?> fc = f.getType();
                        f.setAccessible(true);
                        String fieldVal = fieldList.item(i).getFirstChild().getNodeValue().trim();
                        f.set(o,getBeClassBean(fieldVal,fc));
                    }
                }
            }
        } catch (ParserConfigurationException | SAXException |
                IOException | ClassNotFoundException | InstantiationException |
                IllegalAccessException e) {
            e.printStackTrace();
        }
        return o;
    }

    /**
     * 根据xml 来代理执行方法
     * @param xml xml path
     * @param o 对象 如果执行的全是静态方法则可以传入为null 否则需要传入对应对象
     */
    public static void agentStartUp(String xml,Object o){
        if(YoStringUtils.isEmpty(xml))
            throw new YNullPointerException();
        else if(!new File(xml).exists())
            throw new YFileNotFound(xml);
        try {
            DocumentBuilder db = DocumentBuilderFactory.newInstance().newDocumentBuilder();
            Document dc = db.parse(xml);
            Element cr = dc.getDocumentElement();
            Class<?> c = Class.forName(cr.getAttribute("path"));
            if(o.getClass() != c)
                throw new YClassException(o.getClass(),c);
            Method[] methods = c.getDeclaredMethods();
            NodeList methodList = cr.getElementsByTagName("method");
            for(int i=0;i<methodList.getLength();i++){
                Node method = methodList.item(i);
                NamedNodeMap attrs = method.getAttributes();
                for(Method val : methods){
                    if(!val.getName().equals(attrs.item(0).getNodeValue()))
                        continue;
                    if(val.getReturnType() != void.class)
                        continue;
                    Class<?>[] pc = val.getParameterTypes();
                    String params = methodList.item(i).getFirstChild().getNodeValue().trim();
                    val.invoke(o,params);
                }
            }
        } catch (ParserConfigurationException | SAXException | IOException | ClassNotFoundException
                | IllegalAccessException | InvocationTargetException e) {
            e.printStackTrace();
        }

    }

    private static Object getBeClassBean(String bean,Class<?> clz){
        if(clz == String.class)
            return bean;
        if(clz == Integer.class || clz == int.class)
            return Integer.parseInt(bean);
        if(clz == Long.class || clz == long.class)
            return Long.parseLong(bean);
        if(clz == Character.class || clz == char.class)
            return bean.toCharArray();
        return null;
    }
}
